/* posixTimerStartDemo.c - Demo for executing a signal handler connected to a
                           POSIX TIMER upon expiration of delay specified in 
                           seconds 
*/

/* Copyright 1992 Wind River Systems, Inc. */

/*
modification history
--------------------
02,24sep97,ram  corrected the timer_create function call
11,15may95,ldt  Added comments and include files. stdio.h, logLib.h added
                null parameters to logMsg calls.
01a,10mar94,ms  written.
*/

/* includes */

#include "vxWorks.h"
#include "semLib.h"
#include "signal.h"
#include "sigLib.h"
#include "timers.h"
#include "taskLib.h"
#include "stdio.h"
#include "logLib.h"

/* defines */

#define  TASK_PRI         254   /* Priority of spawned tasks */
#define  TASK_STACK_SIZE  10000 /* stack size for spawned tasks */
#define  DELAY            5     /* 5 seconds delay */ 
#define  TIMER_RELATIVE 0       /*  interval relative to the current time */

/* globals */

LOCAL SEM_ID semId;          /* semaphore ID */

/* funtion prototypes */
LOCAL void demoTask ();      
LOCAL STATUS posixTimerStart (int);
LOCAL void sigHandler (int, int, SIGCONTEXT *);

/*****************************************************************************
 * posixTimerStartDemo - Demonstrates executing a signal handler connected to a
 *                       POSIX TIMER upon expiration of delay specified in 
 *                       seconds.
 *
 *  make sure that the following are INCLUDED in your configAll.h file:
 *    #define INCLUDE_POSIX_SIGNALS    ** POSIX queued signals **
 *    #define INCLUDE_POSIX_TIMERS     ** POSIX timers **
 * 
 * EXAMPLE:
 *
 *     To run this posixTimerStartDemo from the VxWorks shell do as follows: 
 *     -> sp (posixTimerStartDemo)
 *
 */

STATUS posixTimerStartDemo ()
    {
    /* Spawn the demoTask */
    if (taskSpawn ("demoTask", TASK_PRI, 0, TASK_STACK_SIZE, (FUNCPTR) demoTask,
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0) == ERROR)
        {
        perror ("posixTimerStartDemo: Error in spawning demoTask");
        return (ERROR);
        } 

    /* Spwan the posixTimerStart task */
    if (taskSpawn ("posixTimerStart", TASK_PRI, 0, TASK_STACK_SIZE, 
                      (FUNCPTR) posixTimerStart, DELAY, 0, 0, 0, 0, 0, 0, 0, 
                       0, 0) == ERROR)
        {
        perror ("posixTimerStartDemo: Error in spawning posixTimerStart task");
        return (ERROR);
        } 

    /* set up semaphore for synchronization */
    if ((semId = semBCreate (SEM_Q_PRIORITY, SEM_EMPTY)) == NULL)
        {
        perror ("posixTimerStartDemo: semBCreate failed");
        return (ERROR);
        }


    return (OK);
    }

/*****************************************************************************
 * demoTask - Demonstration task that Synchronize with SIGALRM signal 
 *            generated by a POSIX timer
 *
 */

void demoTask ()
    {
        printf (
        "demoTask: Waiting to be synchronized by posix timer SIGALRM signal\n");

        if (semTake (semId, WAIT_FOREVER) == ERROR)
            {
            perror ("intSync: semTake failed");
            return;
            } 
        printf ("\ndemoTask: Synchronization done\n\n");

        /* Do the work that need to be synchronized */
        printf ("demoTask: RUNNING\n");
    }


/*****************************************************************************
 * sigHandler - Signal handler gets executed when SIGALRM signal is generated 
 *              by a POSIX timer.
 */

void sigHandler 
    (
     int sig,     /* signal number */
     int code,    /* additional code */
     SIGCONTEXT *sigContext /* context of task before signal */
     )
     {
         if (sig == SIGALRM)
         {
             logMsg ("\nSignal SIGALRM raised", 0, 0, 0, 0, 0, 0);
         }
         else 
         {
             logMsg ("\nSignal %d received", sig, 0, 0, 0, 0, 0);
         }
         if (semGive (semId) == ERROR)
         {
             logMsg ("Error in giving semaphore", 0, 0, 0, 0, 0, 0);
         }

     }

/*****************************************************************************
 * posixTimerStart - This routine creates a POSIX timer. Signal handler 
 *                   routine will be called to unblock demoTask from the 
 *                   interrupt level upon the expiration of delay (in the 
 *                   specified number of seconds) by the POSIX timer. Finally
 *                   created POSIX timer is deleted. For more information on
 *                   POSIX timers, please refer to the timerLib man pages.
 *
 * RETURNS OK or ERROR
 */

STATUS posixTimerStart 
    (
    int delay      /* delay count in seconds */
    )
    {
    timer_t   timerId;                       /* id  for the posix timer */
    struct    itimerspec   timeToSet;        /* time to be set */  
    struct    timespec     timeValue;        /* timer expiration value */
    struct    timespec     timeInterval;     /* timer period */
    struct    sigaction    signalAction;     /* signal action handler struct */

    /* Intialize sigaction struct */
    signalAction.sa_handler = (VOIDFUNCPTR) sigHandler;
    signalAction.sa_mask    = 0;
    signalAction.sa_flags   = 0;

    /* Initialize timer expiration value */
    timeValue.tv_sec        = delay;
    timeValue.tv_nsec       = 0;

    /* Initialize timer period */
    timeInterval.tv_sec     = delay;
    timeInterval.tv_nsec    = 0;

    /* Set the time to be set value */
    timeToSet.it_value      = timeValue;
    timeToSet.it_interval   = timeInterval;

    /* Connect a signal handler routine to the SIGALRM siganl */
    if (sigaction (SIGALRM, &signalAction, NULL) == ERROR)
        {
        perror ("posixTimerStart: Error in executing sigaction");
        return (ERROR);
        }
    
    printf ("posixTimerStart: Unblock the demoTask in %d seconds\n", delay);
    
    /* Allocate a timer */
    if ((timer_create (CLOCK_REALTIME, NULL,&timerId)) == ERROR)
        {
        perror ("posixTimerStart: Error in allocating a timer");
        return (ERROR);
        }

    /* set the time  until the next expiration and arm the timer (POSIX) */
    if (timer_settime (timerId, TIMER_RELATIVE, &timeToSet, NULL) == ERROR)
        {
        perror ("posixTimerStart: Error in setting time");
        return (ERROR);
        }

    /* suspend this task until delivery of a signal (POSIX)*/
    sigsuspend (0);

    /* delete the previously created timer */
    if (timer_delete (timerId) == ERROR)
        {
        perror ("posixTimerStart: Error in removing timer (POSIX)");
        return (ERROR);
        }

    return (OK);
    }   



